 /*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.dialogs;

 import java.util.Collection ;
 import java.util.Iterator ;

 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IExtension;
 import org.eclipse.core.runtime.IExtensionPoint;
 import org.eclipse.core.runtime.IRegistryChangeEvent;
 import org.eclipse.core.runtime.IRegistryChangeListener;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
 import org.eclipse.jface.preference.IPreferenceNode;
 import org.eclipse.jface.preference.PreferenceManager;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.WorkbenchPlugin;
 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
 import org.eclipse.ui.internal.registry.PreferencePageRegistryReader;

 /**
  * The WorkbenchPreferenceManager is the manager that can handle categories and
  * preference nodes.
  */
 public class WorkbenchPreferenceManager extends PreferenceManager implements
         IExtensionChangeHandler {

     /**
      * Create a new instance of the receiver with the specified seperatorChar
      *
      * @param separatorChar
      */
     public WorkbenchPreferenceManager(char separatorChar) {
         super(separatorChar);
         
         IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
         tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));

         // add a listener for keyword deltas. If any occur clear all page caches
 Platform.getExtensionRegistry().addRegistryChangeListener(
                 new IRegistryChangeListener() {

                     /*
                      * (non-Javadoc)
                      *
                      * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
                      */
                     public void registryChanged(IRegistryChangeEvent event) {
                         if (event.getExtensionDeltas(PlatformUI.PLUGIN_ID,
                                 IWorkbenchRegistryConstants.PL_KEYWORDS).length > 0) {
                             for (Iterator j = getElements(
                                     PreferenceManager.POST_ORDER).iterator(); j
                                     .hasNext();) {
                                 ((WorkbenchPreferenceNode) j.next())
                                         .clearKeywords();
                             }
                         }
                     }
                 });
     }

     /**
      * Add the pages and the groups to the receiver.
      *
      * @param pageContributions
      */
     public void addPages(Collection pageContributions) {

         // Add the contributions to the manager
 Iterator iterator = pageContributions.iterator();
         while (iterator.hasNext()) {
             Object next = iterator.next();
             if (next instanceof WorkbenchPreferenceNode) {
                 WorkbenchPreferenceNode wNode = (WorkbenchPreferenceNode) next;
                 addToRoot(wNode);
                 registerNode(wNode);
             }
         }

     }

     /**
      * Register a node with the extension tracker.
      *
      * @param node
      * register the given node and its subnodes with the extension
      * tracker
      */
     private void registerNode(WorkbenchPreferenceNode node) {
         PlatformUI.getWorkbench().getExtensionTracker().registerObject(
                 node.getConfigurationElement().getDeclaringExtension(), node,
                 IExtensionTracker.REF_WEAK);
         IPreferenceNode[] subNodes = node.getSubNodes();
         for (int i = 0; i < subNodes.length; i++) {
             registerNode((WorkbenchPreferenceNode) subNodes[i]);
         }

     }

     /* (non-Javadoc)
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker, org.eclipse.core.runtime.IExtension)
      */
     public void addExtension(IExtensionTracker tracker, IExtension extension) {
         IConfigurationElement[] elements = extension.getConfigurationElements();
         for (int i = 0; i < elements.length; i++) {
             WorkbenchPreferenceNode node = PreferencePageRegistryReader
                     .createNode(elements[i]);
             if (node == null) {
                 continue;
             }
             registerNode(node);
             String category = node.getCategory();
             if (category == null) {
                 addToRoot(node);
             } else {
                 WorkbenchPreferenceNode parent = null;
                 for (Iterator j = getElements(PreferenceManager.POST_ORDER)
                         .iterator(); j.hasNext();) {
                     WorkbenchPreferenceNode element = (WorkbenchPreferenceNode) j
                             .next();
                     if (category.equals(element.getId())) {
                         parent = element;
                         break;
                     }
                 }
                 if (parent == null) {
                     // Could not find the parent - log
 WorkbenchPlugin
                             .log("Invalid preference page path: " + category); //$NON-NLS-1$
 addToRoot(node);
                 } else {
                     parent.add(node);
                 }
             }
         }
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionAdditionHandler#getExtensionPointFilter()
      */
     private IExtensionPoint getExtensionPointFilter() {
         return Platform.getExtensionRegistry().getExtensionPoint(
                 PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_PREFERENCES);
     }

     /* (non-Javadoc)
      * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, java.lang.Object[])
      */
     public void removeExtension(IExtension extension, Object [] objects) {
         for (int i = 0; i < objects.length; i++) {
             if (objects[i] instanceof WorkbenchPreferenceNode) {
                 WorkbenchPreferenceNode wNode = (WorkbenchPreferenceNode) objects[i];
                 wNode.disposeResources();
                 deepRemove(getRoot(), wNode);
             }
         }
     }

     /**
      * Removes the node from the manager, searching through all subnodes.
      *
      * @param parent
      * the node to search
      * @param nodeToRemove
      * the node to remove
      * @return whether the node was removed
      */
     private boolean deepRemove(IPreferenceNode parent,
             IPreferenceNode nodeToRemove) {
         if (parent == nodeToRemove) {
             if (parent == getRoot()) {
                 removeAll(); // we're removing the root
 return true;
             }
         }

         if (parent.remove(nodeToRemove)) {
             return true;
         }

         IPreferenceNode[] subNodes = parent.getSubNodes();
         for (int i = 0; i < subNodes.length; i++) {
             if (deepRemove(subNodes[i], nodeToRemove)) {
                 return true;
             }
         }
         return false;
     }
 }

